import axios, { AxiosRequestConfig, AxiosPromise } from 'axios'
import { contains } from './utils'
import SchemaConfig from './config-class';

const urlMethods = ['get', 'delete']
// const dataMethods = ['post', 'put', 'patch']

type Method = 'get' | 'delete' | 'post' | 'put' | 'patch'

type UrlMethod = <T = any>(url: string, config?: AxiosRequestConfig) => AxiosPromise<T>
type DataMethod = <T = any>(url: string, data?: any, config?: AxiosRequestConfig) => AxiosPromise<T>
interface Dictionary<T> { [key: string]: T }

interface Options {
  method: Method,
  url: string
}

export function generateAxiosRequest<T>(options: Options, config?: AxiosRequestConfig) {
  return (params: T) => {
    const { method, url } = options
    const isUrlMethod = contains(urlMethods, method)
    if (!config) config = {}
    const axiosParams = [config]
    let axiosFunc = axios[method]

    if (isUrlMethod) {
      config.params = params
    } else {
      axiosParams.unshift(params)
    }
    
    const finalAxiosFunc = isUrlMethod ? (axiosFunc as UrlMethod) : (axiosFunc as DataMethod)
    return finalAxiosFunc<T>(url, ...axiosParams)
  }
}

export function configs2AxiosHOF(schemaConfig: SchemaConfig<any>): (params: any) => AxiosPromise<any> {
  return generateAxiosRequest<typeof schemaConfig.responseDataInterface>(schemaConfig.options, schemaConfig.axiosConfig)
}

export function toAxios(dict: Dictionary<SchemaConfig<any>>) {
  const finalDict = {}
  Object.keys(dict).forEach((key: string) => {
    finalDict[key] = configs2AxiosHOF(dict[key])
  })
  return finalDict
}
